#ifndef	_FIFO_H
#define	_FIFO_H

#include "type.h"
#include "Etf_Config.h"
/*!
 * FIFO structure
 */
typedef struct Fifo_s
{
    etf_uint16_t                Begin;
    etf_uint16_t                End;
    etf_uint8_t *               Data;
    etf_uint16_t                Size;
}Fifo_t;

etf_inline etf_uint16_t FifoNext( Fifo_t *fifo, etf_uint16_t index ){
    return ( index + 1 ) % fifo->Size;
}

/*!
 * Initializes the FIFO structure
 *
 * \param [IN] fifo   Pointer to the FIFO object
 * \param [IN] buffer Buffer to be used as FIFO
 * \param [IN] size   Size of the buffer
 */
etf_inline void FifoInit( Fifo_t *fifo, etf_uint8_t *buffer, etf_uint16_t size ){
    fifo->Begin                                         = 0;
    fifo->End                                           = 0;
    fifo->Data                                          = buffer;
    fifo->Size                                          = size;
}
/*!
 * Pushes data to the FIFO
 *
 * \param [IN] fifo Pointer to the FIFO object
 * \param [IN] data Data to be pushed into the FIFO
 */
etf_inline void FifoPush( Fifo_t *fifo, etf_uint8_t data ){

    ETF_IRQ_DISABLE();
    fifo->End                                           = FifoNext( fifo, fifo->End );
    fifo->Data[fifo->End]                               = data;
    ETF_IRQ_ENABLE()
}
/*!
 * Pops data from the FIFO
 *
 * \param [IN] fifo Pointer to the FIFO object
 * \retval data     Data popped from the FIFO
 */
etf_inline etf_uint8_t FifoPop( Fifo_t *fifo ){
    etf_uint8_t                 data;
    
    ETF_IRQ_DISABLE();
    data                                                = fifo->Data[FifoNext( fifo, fifo->Begin )];
    fifo->Begin                                         = FifoNext( fifo, fifo->Begin );
    ETF_IRQ_ENABLE()
    return data;
}

/*!
 * Flushes the FIFO
 *
 * \param [IN] fifo   Pointer to the FIFO object
 */
etf_inline void FifoFlush( Fifo_t *fifo ){
    fifo->Begin                                         = 0;
    fifo->End                                           = 0;
}

/*!
 * Checks if the FIFO is empty
 *
 * \param [IN] fifo   Pointer to the FIFO object
 * \retval isEmpty    true: FIFO is empty, false FIFO is not empty
 */
etf_inline etf_uint8_t IsFifoEmpty( Fifo_t *fifo ){
    return ( fifo->Begin == fifo->End );
}

/*!
 * Checks if the FIFO is full
 *
 * \param [IN] fifo   Pointer to the FIFO object
 * \retval isFull     true: FIFO is full, false FIFO is not full
 */
etf_inline etf_uint8_t IsFifoFull( Fifo_t *fifo ){
    return ( FifoNext( fifo, fifo->End ) == fifo->Begin );
}

#endif


